package com.untour.im.client.handler;

import com.untour.im.client.ClientArtisan;
import com.untour.im.client.command.ClientPacketEncodec;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.nio.NioEventLoopGroup;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 客户端心跳处理
 */
@Slf4j
@ChannelHandler.Sharable
public class ClientHeartBeatHandler extends ChannelInboundHandlerAdapter {

    // 5秒发送一次心跳
    private static final int HEARTBEAT_INTERVAL = 5;

    private Bootstrap bootstrap;
    private AtomicInteger maxReconnectAttempts;

    private AtomicBoolean forceOffline;

    private NioEventLoopGroup group;
    public ClientHeartBeatHandler(Bootstrap bootstrap, NioEventLoopGroup group,
                                  AtomicInteger maxReconnectAttempts,
                                  AtomicBoolean forceOffline) {
        this.bootstrap = bootstrap;
        this.maxReconnectAttempts = maxReconnectAttempts;
        this.group = group;
        this.forceOffline = forceOffline;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        this.scheduleSendHeartBeat(ctx);
        super.channelActive(ctx);
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 打印提示信息
        System.err.println("运行中断开重连。。。");
        // 调用客户端的connect方法进行重连
        if(forceOffline.get()){
            System.err.println("强制下线~~~~");
            ctx.channel().close();
            ctx.close();
            group.shutdownGracefully();
            System.exit(1);
        } else {
            ClientArtisan.connect(bootstrap, group, maxReconnectAttempts, forceOffline);
        }
    }

    private void scheduleSendHeartBeat(ChannelHandlerContext ctx) {
        // 此处无需使用scheduleAtFixedRate，因为如果通道失效后，就无需在发起心跳了，按照目前的方式是最好的：成功一次安排一次
        ctx.executor().schedule(() -> {
            if (ctx.channel().isActive()) {
                log.info("客户端定时发送心跳！");
                ClientPacketEncodec.INSTANCE.sendHeartBeatRequestMessage(ctx);
                scheduleSendHeartBeat(ctx);
            }
        }, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
    }
}
